package com.javastudy.jdkfeature.jdk5.enums;

/**
 * 创建枚举类型要使用 enum 关键字，隐含了所创建的类型都是 java.lang.Enum 类的子类（java.lang.Enum 是一个抽象类）。
 * 枚举类型符合通用模式 Class Enum<E extends Enum<E>>，而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中，
 * 在这里，每个值的名称都被转换成一个字符串，并且序数设置表示了此设置被创建的顺序。
 * 常见的用法
 * 用法一：常量
 * 用法二：switch
 * 用法三：向枚举中添加新方法
 * 用法四：覆盖枚举的方法
 * 用法五：实现接口： 所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承，所以枚举对象不能再继承其他类, ColorBehaviour
 * 用法六：使用接口组织枚举, FoodIF
 * 用法七：关于枚举集合的使用:java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复；EnumMap中的 key是enum类型，而value则可以是任意类型。
 *
 * 枚举类型对象之间的值比较，是可以使用==，直接来比较值，是否相等的，不是必须使用equals方法
 *
 * 枚举类名建议带上Enum后缀，枚举成员名称需要全大写，单词间用下划线隔开。
 * 枚举其实就是特殊的常量类i，且构造方法被默认强制是私有
 *
 * 原理分析
 * enum 的语法结构尽管和 class 的语法不一样，但是经过编译器编译之后产生的是一个class文件。该class文件经过反编译可以看到实际上是生成了一个类，该类继承了java.lang.Enum<E>。
 * 所以，实际上 enum 就是一个 class，只不过 java 编译器帮我们做了语法的解析和编译而已。
 * 可以把 enum 看成是一个普通的 class，它们都可以定义一些属性和方法，不同之处是：enum 不能使用 extends 关键字继承其他类，因为 enum 已经继承了 java.lang.Enum（java是单一继承）。
 * enum 对象的常用方法介绍
 int compareTo(E o) -  比较此枚举与指定对象的顺序。
 Class<E> getDeclaringClass()-  返回与此枚举常量的枚举类型相对应的 Class 对象。
 String name() -  返回此枚举常量的名称，在其枚举声明中对其进行声明。
 int ordinal() -  返回枚举常量的序数（它在枚举声明中的位置，其中初始常量序数为零）。
 String toString() -  返回枚举常量的名称，它包含在声明中。
 static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) -  返回带指定名称的指定枚举类型的枚举常量。
 */
public class EnumTest {

    public void forSwitch(WeekEnum nextDay) {
        WeekEnum week = WeekEnum.MON;
        switch (nextDay) {
            case SUN:
                week = WeekEnum.SUN;
                break;
            case SAT:
                week = WeekEnum.SAT;
                break;
            default:
                week = WeekEnum.MON;
                break;
        }
    }

    ///// 用法三：向枚举中添加新方法
    // 如果打算自定义自己的方法，那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。
    public enum Color {
        RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
        // 成员变量
        private String name;
        private int index;

        // 构造方法
        private Color(String name, int index) {
            this.name = name;
            this.index = index;
        }

        // 普通方法  用法三
        public static String getName(int index) {
            for (Color c : Color.values()) {
                if (c.getIndex() == index) {
                    return c.name;
                }
            }
            return null;
        }

        //覆盖方法  用法四
        @Override
        public String toString() {
            return this.index + "_" + this.name;
        }

        // get set 方法
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getIndex() {
            return index;
        }

        public void setIndex(int index) {
            this.index = index;
        }
    }

    public static void main(String[] args) {
        forEnum();
        useEnumInJava();
    }

    /**
     * 循环枚举,输出ordinal属性；若枚举有内部属性，则也输出。(说的就是我定义的TYPE类型的枚举的typeName属性)
     */
    private static void forEnum() {
        for (SimpleEnum simpleEnum : SimpleEnum.values()) {
            System.out.println(simpleEnum + "  ordinal  " + simpleEnum.ordinal());
        }
        System.out.println("------------------");
        for (TYPE type : TYPE.values()) {
            System.out.println("type = " + type + "    type.name = " + type.name() + "   typeName = " + type.getTypeName() + "   ordinal = " + type.ordinal());
        }
    }

    /**
     * 在Java代码使用枚举
     */
    private static void useEnumInJava() {
        String typeName = "f5";
        TYPE type = TYPE.fromTypeName(typeName);
        if (TYPE.BALANCE.equals(type)) {
            System.out.println("根据字符串获得的枚举类型实例跟枚举常量一致");
        } else {
            System.out.println("大师兄代码错误");
        }

    }

    /**
     * 季节枚举(不带参数的枚举常量)这个是最简单的枚举使用实例
     * Ordinal 属性，对应的就是排列顺序，从0开始。
     */
    private enum SimpleEnum {
        SPRING,
        SUMMER,
        AUTUMN,
        WINTER
    }


    /**
     * 常用类型(带参数的枚举常量，这个只是在书上不常见，实际使用还是很多的，看懂这个，使用就不是问题啦。)
     */
    private enum TYPE {
        FIREWALL("firewall"),
        SECRET("secretMac"),
        BALANCE("f5");

        private String typeName;

        TYPE(String typeName) {
            this.typeName = typeName;
        }

        /**
         * 根据类型的名称，返回类型的枚举实例。
         *
         * @param typeName 类型名称
         */
        public static TYPE fromTypeName(String typeName) {
            for (TYPE type : TYPE.values()) {
                if (type.getTypeName().equals(typeName)) {
                    return type;
                }
            }
            return null;
        }

        public String getTypeName() {
            return this.typeName;
        }
    }
}


